home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / zmdm / rz.c < prev    next >
C/C++ Source or Header  |  1993-06-26  |  28KB  |  1,395 lines

  1. /*
  2.  *                ACKNOWLEDGEMENTS
  3.  *
  4.  *    ZMDM was derived from rz/sz for Unix  posted by 
  5.  *    Chuck Forsberg (...!tektronix!reed!omen!caf ). We
  6.  *    thank him for his excellent code, and for giving
  7.  *    us permission to use and distribute his code and
  8.  *    documentation.
  9.  *
  10.  *    Atari St version by:
  11.  *        Jwahar Bammi
  12.  *            usenet: cwruecmp!bammi@decvax.UUCP
  13.  *            csnet:  bammi@cwru.edu
  14.  *            arpa:   bammi@cwru.edu
  15.  *            CompuServe: 71515,155
  16.  */
  17.  
  18. #define RVERSION "rz 1.14 01-15-87"
  19. #define RSTVERSION "rz 1.01 03-07-87"
  20. #define OS    "Unix V7/BSD"
  21.  
  22. /* #define RDEBUG */            /* a lot of debugging garb */
  23.  
  24. /*
  25.  *    ATARI ST series implementation notes:
  26.  *
  27.  *        - the following command line options were removed as they
  28.  *          were either  not applicable to the ST environment or
  29.  *          were not deemed reasonable (by me - ofcourse).
  30.  *            1    Not Applicable here as we have a seperate
  31.  *                serial port.
  32.  *            7    In this day and age? Forget it, get another m/c.
  33.  *            a/b    Ascii/Binary - the receive mode (if not
  34.  *                over-ridden by the sender) is automatically
  35.  *                selected depending on the extention given
  36.  *                in the incoming file name. This idea was
  37.  *                present in earlier rz/sz, i wonder why such
  38.  *                a convenient feature was dropped (Chuck ??).
  39.  *                This feature is relevant to ZMODEM only in rz,
  40.  *                as the sender determines the file mode in
  41.  *                XMODEM/YMODEM transfers.
  42.  *                B    Note that `B' has a special meaning.
  43.  *                Specifying -B will force override to
  44.  *                binary mode for each incoming file. Useful
  45.  *                 when doing St-to-St transfers.
  46.  *            D    There is no /dev/null on the ST's
  47.  *            u    not applicable to TOS. Upper and lower
  48.  *                case file names are the same. All the
  49.  *                applicable routines like uncap() and
  50.  *                IsAnyLower() were zapped.
  51.  *
  52.  *        - The    [-][v]rzCOMMAND style of invocation was dropped
  53.  *          as there is no good way to do pipes without the 
  54.  *          microRtx kernal. All references to Pipe and popen()
  55.  *          were zapped.
  56.  *        - Verbose is always set to 2 by automatically, as we know that
  57.  *          stdout != stderr. This can be overridden
  58.  *          by specifying -q to ensure that Verbose = 0
  59.  *        - The idea of a PUBDIR and Restricted paths in the origonal
  60.  *          code  was dropped totally as it is not applicable
  61.  *          to the single owner ST environment. 1 man 1 machine.
  62.  *        - CRCTABLE is default always, hey we have plenty of memory!.
  63.  *        - LOGFILE renamed to 'rzlog/szlog' as we don't always have
  64.  *          a meaningful environment to pick up TMPDIR from (like when
  65.  *          running from the desktop).
  66.  *            - When a subdirectory in an incoming path name is not
  67.  *          present it is created.
  68.  *        - The file mode transmitted is 0S00 where S is derived from
  69.  *          the Read/Write attribute of the file on the ST
  70.  *        - When a file mode is received, only the owner bits are
  71.  *          are checked. If it was read only (r--) on the Unix sytem
  72.  *          then it is given read only attribute on the ST, read-write
  73.  *          otherwise.
  74.  *        - Of course all the I/O was completely redone on the ST.
  75.  *        - You will find two versions of VARARGS routines like log,
  76.  *          one that takes int args, and the other that takes long
  77.  *          (address) args, since sizeof(int) != sizeof(long)
  78.  *          and sizeof(int) != sizeof(pointer) on the ST.
  79.  *
  80.  *    ST v1.01
  81.  *     added support for 32 bit CRC's for Zmodem ++jrb
  82.  *
  83.  */
  84.         
  85. /*% cc -DNFGVMIN -DCRCTABLE -K -O % -o rz; size rz
  86.  *
  87.  * rz.c By Chuck Forsberg
  88.  *
  89.  *    cc -O rz.c -o rz        USG (3.0) Unix
  90.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  91.  *
  92.  *    ln rz rb            For either system
  93.  *
  94.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  95.  *                    login shell. rzrmail then calls
  96.  *                    rmail(1) to deliver mail.
  97.  *
  98.  *        define CRCTABLE to use table driven CRC
  99.  *
  100.  *  Unix is a trademark of Western Electric Company
  101.  *
  102.  * A program for Unix to receive files and commands from computers running
  103.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  104.  *  rz uses Unix buffered input to reduce wasted CPU time.
  105.  *
  106.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  107.  * "COMMAND filename"
  108.  *
  109.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  110.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  111.  *  character reads for these systems. Added 7-01-84 CAF
  112.  *
  113.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  114.  *
  115.  *  NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN]
  116.  *  doesn't seem to work (even though it compiles without error!).
  117.  *
  118.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  119.  */
  120.  
  121.  
  122. #include "zmdm.h"
  123. #include "common.h"
  124. #include "zmodem.h"
  125.  
  126. static unsigned long SaveIntr;
  127.  
  128. #ifdef MWC
  129. extern FILE  *fopen();
  130. #else
  131. extern FILE  *fopen(), *fopenb();
  132. #endif
  133.  
  134. /* called by simulated signal interrupt or terminate to clean things up */
  135. bibi(n)
  136. int n;
  137. {
  138.  
  139.     if (Zmodem)
  140.         zmputs(Attn);
  141.     canit(); mode(0);
  142.     fprintf(stderr, "\r\nrz: caught signal %d; exiting", n);
  143.     if (fout != -1)
  144.     {
  145.         if (stfclose(fout) != 0)
  146.         {
  147.             fprintf(stderr, "\r\nfile close ERROR\n");
  148.         }
  149.         fout = (-1);
  150.  
  151.     }
  152.  
  153. #ifdef RDEBUG
  154.     if (logf != (FILE *)NULL)
  155.         fclose(logf);
  156. #endif
  157.     aexit(128+n);
  158. }
  159.  
  160. dorz(argc, argv)
  161. int argc;
  162. char **argv;
  163. {
  164.     register char *cp;
  165.     register int npats;
  166.     char **patts;
  167.     int exitcode;
  168.  
  169.     SendType = 0;
  170.     Rxtimeout = 100;
  171.     exitcode = 0;
  172.  
  173.     initz();
  174.  
  175.     chkinvok(argv[0]);     /* if called as  'rb' set flag */
  176.     npats = 0;
  177.     SaveIntr = Setexc(0x0102, -1L);
  178.     BusErr   = Setexc(2, -1L);
  179.     AddrErr  = Setexc(3, -1L);
  180.     vdebug = 0;
  181.  
  182.     while (--argc)
  183.     {
  184.         cp = *++argv;
  185.         if (*cp == '-')
  186.         {
  187.             while( *++cp)
  188.             {
  189.                 switch(*cp)
  190.                 {
  191.                 case '+':
  192.                     Lzmanag = ZMAPND; break;
  193.                 case 'B':
  194.                     ForceBinary=TRUE; break;
  195.                 case 'c':
  196.                     Crcflg=TRUE; break;
  197.                 case 'p':
  198.                     Lzmanag = ZMPROT;  break;
  199.                 case 'q':
  200.                     Quiet=TRUE; Verbose=0; break;
  201.                 case 't':
  202.                     if (--argc < 1) {
  203.                         rusage();
  204.                         return(1);
  205.                     }
  206.                     Rxtimeout = atoi(*++argv);
  207.                     if (Rxtimeout<10 || Rxtimeout>1000)
  208.                     {
  209.                         rusage();
  210.                         return(1);
  211.                     }
  212.                     break;
  213.                 case 'v':
  214.                     ++Verbose; break;
  215.                 default:
  216.                     rusage();
  217.                     return(1);
  218.                 }
  219.             }
  220.         }
  221.         else if ( !npats && argc>0)
  222.         {
  223.             if (argv[0][0])
  224.             {
  225.                 npats=argc;
  226.                 patts=argv;
  227.             }
  228.         }
  229.     }
  230.  
  231.     if (npats > 1)
  232.     {
  233.         rusage();
  234.         return(1);
  235.     }
  236.  
  237. #ifdef RDEBUG
  238.     if (Verbose > 2)
  239.     {
  240.         if ((logf = fopen(RLOGFILE, "a"))== (FILE *)NULL)
  241.         {
  242.             fprintf(stderr, "Can't open log file %s\n",RLOGFILE);
  243.             return(0200);
  244.         }
  245.         fprintf(logf, "Progname=%s\n", Progname);
  246.         vdebug = 1;
  247.     }
  248. #endif
  249.  
  250.     if ( !Quiet)
  251.     {
  252.         if (Verbose == 0)
  253.             Verbose = 2;
  254.     }
  255.  
  256.     Setexc(0x0102, bibi);
  257.  
  258.     Setexc(2, buserr);
  259.     Setexc(3, addrerr);
  260.  
  261.     if((exitcode = setjmp(abrtjmp)))
  262.     {
  263.         /* on Contrl-C */
  264.         canit();
  265.         Setexc(2, BusErr);
  266.         Setexc(3, AddrErr);
  267.         Setexc(0x0102, SaveIntr);
  268.         return(exitcode);
  269.     }
  270.     
  271.     if(setjmp(busjmp))
  272.     {
  273.         /* On a bus error - instead of 2 bombs */
  274.         fprintf(stderr,"\r\nFATAL: Bus Error\n\n");
  275. #ifdef RDEBUG
  276.         if(logf != (FILE *)NULL)
  277.             fclose(logf);
  278. #endif
  279.         if(fout != -1)
  280.         {
  281.             if (stfclose(fout) != 0)
  282.             {
  283.                 fprintf(stderr, "\r\nfile close ERROR\n");
  284.             }
  285.             fout = (-1);
  286.         }
  287.         canit();
  288.         Setexc(2, BusErr);
  289.         Setexc(3, AddrErr);
  290.         Setexc(0x0102, SaveIntr);
  291.  
  292.         return(2);
  293.     }
  294.  
  295.     if(setjmp(addrjmp))
  296.     {
  297.         /* On address error - instead of 3 bombs */
  298.         fprintf(stderr,"\r\nFATAL: Address Error\n\n");
  299. #ifdef RDEBUG
  300.         if(logf != (FILE *)NULL)
  301.             fclose(logf);
  302. #endif
  303.         if(fout != -1)
  304.         {
  305.             if (stfclose(fout) != 0)
  306.             {
  307.                 fprintf(stderr, "\r\nfile close ERROR\n");
  308.             }
  309.             fout = (-1);
  310.         }
  311.         canit();
  312.         Setexc(2, BusErr);
  313.         Setexc(3, AddrErr);
  314.         Setexc(0x0102, SaveIntr);
  315.  
  316.         return(3);
  317.     }
  318.  
  319.     mode(1);
  320.  
  321.     if (wcreceive(npats, patts)==ERROR)
  322.     {
  323.         exitcode=0200;
  324.         canit();
  325.     }
  326.  
  327.     mode(0);
  328.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  329.         canit();
  330.  
  331. #ifdef RDEBUG
  332.     if(logf != (FILE *)NULL)
  333.         fclose(logf);
  334. #endif
  335.  
  336.     if(fout != -1)
  337.     {
  338.         if (stfclose(fout) != 0)
  339.         {
  340.             fprintf(stderr, "\r\nfile close ERROR\n");
  341.         }
  342.         fout = (-1);
  343.     }
  344.     Setexc(2, BusErr);
  345.     Setexc(3, AddrErr);
  346.     Setexc(0x0102, SaveIntr);
  347.  
  348.      return(exitcode); 
  349. }
  350.  
  351.  
  352. rusage()
  353. {
  354.     fprintf(stderr,
  355.         "%s for %s by ST Enthusiasts at Case Western Reserve University\n",
  356.           RSTVERSION, STOS);
  357.     fprintf(stderr, "\tBased on %s for %s by Chuck Forsberg\n\n",
  358.         RVERSION, OS);
  359.  
  360.     fprintf(stderr,"Usage:    rz [-Bpqtv]        (ZMODEM Batch)\n");
  361.     fprintf(stderr,"or    rb [-qtv]        (YMODEM Batch)\n");
  362.     fprintf(stderr,"or    rz [-cqtv] file            (XMODEM or XMODEM-1k)\n");
  363.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  364.     fprintf(stderr,"          -q Quiet suppresses verbosity\n");
  365.     fprintf(stderr,"      -t TIM Change timeout to TIM tenths of seconds\n");
  366.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  367.     fprintf(stderr,"      -p Protect existing dest. file by skipping\n");
  368.     fprintf(stderr,"         transfer if the dest. file exists (ZMODEM ONLY)\n\n");
  369.  
  370.  
  371.     if(fout != -1)
  372.     {
  373.         if (stfclose(fout) != 0)
  374.         {
  375.             fprintf(stderr, "\r\nfile close ERROR\n");
  376.         }
  377.         fout = (-1);
  378.     }
  379.  
  380. #ifdef RDEBUG
  381.     if(logf != (FILE *)NULL)
  382.         fclose(logf);
  383. #endif
  384.  
  385.     return(1);
  386. }
  387.  
  388.  
  389. /*
  390.  * Let's receive something already.
  391.  */
  392. wcreceive(argc, argp)
  393. int argc;
  394. char **argp;
  395. {
  396.     register int c;
  397.  
  398.     if (Batch || argc==0)
  399.     {
  400.         Crcflg=(Wcsmask==0377);
  401.         if ( !Quiet)
  402.             fprintf(stderr, "\n%s: ready (CTRL-C to cancel)\n\n",
  403.                 Progname);
  404.  
  405.         if (c=tryz())
  406.         {
  407.             if (c == ZCOMPL)
  408.                 return OK;
  409.             if (c == ERROR)
  410.                 goto fubar;
  411.             c = rzfiles();
  412.             if (c)
  413.                 goto fubar;
  414.         }
  415.         else
  416.         {
  417.             for (;;)
  418.             {
  419.                 if (wcrxpn(secbuf)== ERROR)
  420.                     goto fubar;
  421.                 if (secbuf[0]==0)
  422.                     return OK;
  423.                 if (procheader(secbuf) == ERROR)
  424.                     goto fubar;
  425.                 if (wcrx()==ERROR)
  426.                     goto fubar;
  427.             }
  428.         }
  429.     } 
  430.     else
  431.     {
  432.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  433.  
  434.         strcpy(Pathname, *argp);
  435.         fprintf(stderr, "\n%s: ready to receive %s (CTRL-C to Cancel)\n\n",
  436.             Progname, Pathname);
  437. #ifdef RDEBUG
  438.         if(logf != (FILE *)NULL)
  439.             fprintf(logf, "\nrz: ready to receive %s ", Pathname);
  440. #endif
  441.  
  442.         if((fout = stfopen(Pathname,"w")) <= 0)
  443.             return ERROR;
  444.         if (wcrx()==ERROR)
  445.             goto fubar;
  446.     }
  447.     return OK;
  448.  
  449. fubar:
  450.     canit();
  451.  
  452.     if (fout != -1)
  453.     {
  454.         if (stfclose(fout) != 0)
  455.         {
  456.             fprintf(stderr, "\r\nfile close ERROR\n");
  457.         }
  458.         fout = (-1);
  459.     }
  460.  
  461.     return ERROR;
  462. }
  463.  
  464.  
  465. /*
  466.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  467.  * Length is indeterminate as long as less than Blklen
  468.  * A null string represents no more files (YMODEM)
  469.  */
  470. wcrxpn(rpn)
  471. char *rpn;    /* receive a pathname */
  472. {
  473.     register int c;
  474.  
  475.     PURGELINE;
  476.  
  477. et_tu:
  478.     Firstsec=TRUE;  Eofseen=FALSE;
  479.     sendline(Crcflg?WANTCRC:NAK);
  480.     Lleft=0;    /* Do read next time ... */
  481.     while ((c = wcgetsec(rpn, 100)) != 0)
  482.     {
  483.         llog( "Pathname fetch returned %d\n", c);
  484.         if (c == WCEOT)
  485.         {
  486.             sendline(ACK);
  487.             Lleft=0;    /* Do read next time ... */
  488.             readline(1);
  489.             goto et_tu;
  490.         }
  491.         return ERROR;
  492.     }
  493.     sendline(ACK);
  494.     return OK;
  495. }
  496.  
  497. /*
  498.  * Adapted from CMODEM13.C, written by
  499.  * Jack M. Wierda and Roderick W. Hart
  500.  */
  501.  
  502. wcrx()
  503. {
  504.     register int sectnum, sectcurr;
  505.     register char sendchar;
  506.     int cblklen;            /* bytes to dump this block */
  507.  
  508.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  509.     sendchar=Crcflg?WANTCRC:NAK;
  510.  
  511.     for (;;)
  512.     {
  513.         sendline(sendchar);    /* send it now, we're ready! */
  514.         Lleft=0;    /* Do read next time ... */
  515.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  516.         report(sectcurr);
  517.         if (sectcurr==(sectnum+1 &Wcsmask))
  518.         {
  519.             sectnum++;
  520.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  521.             if (putsec(secbuf, cblklen)==ERROR)
  522.                 return ERROR;
  523.             if ((Bytesleft-=cblklen) < 0)
  524.                 Bytesleft = 0;
  525.             sendchar=ACK;
  526.         }
  527.         else if (sectcurr==(sectnum&Wcsmask))
  528.         {
  529.             log2( "Received dup Sector\n");
  530.             sendchar=ACK;
  531.         }
  532.         else if (sectcurr==WCEOT)
  533.         {
  534.             if (closeit())
  535.                 return ERROR;
  536.             sendline(ACK);
  537.             Lleft=0;    /* Do read next time ... */
  538.             return OK;
  539.         }
  540.         else if (sectcurr==ERROR)
  541.             return ERROR;
  542.         else
  543.         {
  544.             log2( "Sync Error\n");
  545.             return ERROR;
  546.         }
  547.     }
  548. }
  549.  
  550.  
  551. /*
  552.  * Wcgetsec fetches a Ward Christensen type sector.
  553.  * Returns sector number encountered or ERROR if valid sector not received,
  554.  * or CAN CAN received
  555.  * or WCEOT if eot sector
  556.  * time is timeout for first char, set to 4 seconds thereafter
  557.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  558.  *    (Caller must do that when he is good and ready to get next sector)
  559.  */
  560. wcgetsec(rxbuf, maxtime)
  561. char *rxbuf;
  562. int maxtime;
  563. {
  564.     register int checksum, wcj, firstch;
  565.     register unsigned int oldcrc;
  566.     register char *p;
  567.     int sectcurr;
  568.  
  569.     for (Lastrx=errors=0; errors<RETRYMAX; errors++)
  570.     {
  571.  
  572.         if ((firstch=readline(maxtime))==STX)
  573.         {
  574.             Blklen=KSIZE; goto get2;
  575.         }
  576.         if (firstch==SOH)
  577.         {
  578.             Blklen=SECSIZ;
  579. get2:
  580.             sectcurr=readline(1);
  581.             if ((sectcurr+(oldcrc=readline(1)))==Wcsmask)
  582.             {
  583.                 oldcrc=checksum=0;
  584.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; )
  585.                 {
  586.                     if ((firstch=readline(1)) < 0)
  587.                         goto bilge;
  588.                     oldcrc=updcrc(firstch, oldcrc);
  589.                     checksum += (*p++ = firstch);
  590.                 }
  591.                 if ((firstch=readline(1)) < 0)
  592.                     goto bilge;
  593.                 if (Crcflg)
  594.                 {
  595.                     oldcrc=updcrc(firstch, oldcrc);
  596.                     if ((firstch=readline(1)) < 0)
  597.                         goto bilge;
  598.                     oldcrc=updcrc(firstch, oldcrc);
  599.                     if (oldcrc & 0xFFFF)
  600.                         llog("CRC=0%o\n", oldcrc);
  601.                     else
  602.                     {
  603.                         Firstsec=FALSE;
  604.                         return sectcurr;
  605.                     }
  606.                 }
  607.                 else if (((checksum-firstch)&Wcsmask)==0)
  608.                 {
  609.                     Firstsec=FALSE;
  610.                     return sectcurr;
  611.                 }
  612.                 else
  613.                     log2( "Checksum Error\n");
  614.             }
  615.             else
  616.                 log2("Sector number garbled 0%o 0%o\n",
  617.                  sectcurr, oldcrc);
  618.         }
  619.         /* make sure eot really is eot and not just mixmash */
  620.  
  621.         else if (firstch==EOT && Lleft==0)
  622.             return WCEOT;
  623.  
  624.         else if (firstch==CAN)
  625.         {
  626.             if (Lastrx==CAN)
  627.             {
  628.                 log2( "Sender CANcelled\n");
  629.                 return ERROR;
  630.             }
  631.             else
  632.             {
  633.                 Lastrx=CAN;
  634.                 continue;
  635.             }
  636.         }
  637.         else if (firstch==TIMEOUT)
  638.         {
  639.             if (Firstsec)
  640.                 goto humbug;
  641. bilge:
  642.             log2( "Timeout\n");
  643.         }
  644.         else
  645.             llog( "Got 0%o sector header\n", firstch);
  646.  
  647. humbug:
  648.         Lastrx=0;
  649.         while(readline(1)!=TIMEOUT)
  650.             ;
  651.         if (Firstsec)
  652.         {
  653.             sendline(Crcflg?WANTCRC:NAK);
  654.             Lleft=0;    /* Do read next time ... */
  655.         }
  656.         else
  657.         {
  658.             maxtime=40; sendline(NAK);
  659.             Lleft=0;    /* Do read next time ... */
  660.         }
  661.     }
  662.     /* try to stop the bubble machine. */
  663.     canit();
  664.     return ERROR;
  665. }
  666.  
  667. /*
  668.  * This version of readline is reasonably well suited for
  669.  * reading many characters.
  670.  * timeout is in tenths of seconds
  671.  */
  672. int readline(timeout)
  673. int timeout;
  674. {
  675.     register int n;
  676.     static char *cdq;    /* pointer for removing chars from linbuf */
  677.  
  678.     if (--Lleft >= 0)
  679.     {
  680. #ifdef RDEBUG
  681.         if (Verbose > 8)
  682.         {
  683.             fprintf(logf, "%02x ", *cdq&0377);
  684.         }
  685. #endif
  686.  
  687.         return (*cdq++ & Wcsmask);
  688.     }
  689. /*    n = timeout/10; */
  690.     n = timeout >> 3;  /* close enough for rock and roll - see alarm() */
  691.     if (n < 2)
  692.         n = 3;
  693. #ifdef RDEBUG
  694.     if (Verbose > 3)
  695.         fprintf(logf, "Calling read: n=%d ", n);
  696. #endif
  697.  
  698.     if (setjmp(tohere))
  699.     {
  700.         Lleft = 0;
  701. #ifdef RDEBUG
  702.         if (Verbose>3)
  703.         {
  704.             fprintf(stderr, "Readline:TIMEOUT\n");
  705.             fprintf(logf, "Readline:TIMEOUT\n");
  706.  
  707.         }
  708. #endif
  709.         return TIMEOUT;
  710.     }
  711.     stalarm(n);
  712.     Lleft=read_modem(cdq=linbuf, Readnum);
  713.     stalarm(0);
  714.  
  715. #ifdef RDEBUG
  716.     if (Verbose > 3)
  717.     {
  718.         fprintf(logf, "Read returned %d bytes\n", Lleft);
  719.     }
  720. #endif
  721.  
  722.     if (Lleft < 1)
  723.         return TIMEOUT;
  724.     --Lleft;
  725.  
  726. #ifdef RDEBUG
  727.     if (Verbose > 8)
  728.     {
  729.         fprintf(logf, "%02x ", *cdq&0377);
  730.     }
  731. #endif
  732.  
  733.     return (*cdq++ & Wcsmask);
  734. }
  735.  
  736.  
  737.  
  738.  
  739. /*
  740.  * Process incoming file information header
  741.  */
  742. procheader(name)
  743. char *name;
  744. {
  745.     register char  *p;
  746.     register int dot;
  747.     char openmode[4];
  748.     extern int strlen();
  749.  
  750.     /* convert to ST style path names */
  751.     for( p = name; *p != '\0'; p++)
  752.     {
  753.         if(*p == '/')
  754.             *p = '\\';
  755.     }
  756.     
  757.     /* pick out the last extention in the filename in each part of path */
  758.     while(p != name)
  759.     {
  760.         dot = 0; p-- ;
  761.         while((p != name) && (*p != '\\'))
  762.         {
  763.             if(*p == '.')
  764.             {
  765.                 if(dot == 0)
  766.                 {
  767.                     dot = 1;
  768.                 }
  769.                 else
  770.                 {
  771.                    /* replace all but the last dot with '_' */
  772.                     *p = '_';
  773.                 }
  774.             }
  775.             p--;
  776.         }
  777.     }
  778.                 
  779.     /* set default parameters and overrides */
  780.     strcpy(openmode,"w");
  781.  
  782.     Thisbinary = isbinary(name);
  783.  
  784.     if (Lzmanag)
  785.         zmanag = Lzmanag;
  786.  
  787.     /*
  788.      *  Process ZMODEM remote file management requests
  789.      */
  790.     if ( zconv == ZCNL)    /* Remote ASCII override */
  791.         Thisbinary = 0;
  792.     if (zconv == ZCBIN)    /* Remote Binary override */
  793.         ++Thisbinary;
  794.     else if (zmanag == ZMAPND)
  795.         strcpy(openmode, "a");
  796.  
  797.     if (ForceBinary == TRUE )    /* local binary force override */
  798.         ++Thisbinary;
  799.  
  800.     /* ZMPROT check for existing file */
  801.     if (zmanag == ZMPROT && existf(name, "r"))
  802.     {
  803.         return ERROR;
  804.     }
  805.  
  806. /* ATARI ST NOTE:
  807.  *    We will not accept rooted paths ie. paths that begin in '\' or '.\'
  808.  *    If the incoming filename is rooted, we skip the beginning
  809.  *    '\'   '.\'  or  '..\'
  810.  */
  811.  
  812.     if( (name[0] == '\\') || (name[0] == '.')  )
  813.     {
  814.         /* skip over the leading stuff */
  815.         if(name[0] == '\\')
  816.             name = &name[1];
  817.         else
  818.         {
  819.             if(name[1] == '.')
  820.                 name = &name[3];  /* Skip the "..\" */
  821.             else
  822.                 name = &name[2];  /* Skip the ".\"  */
  823.         }
  824.     }
  825.  
  826.     /* ST addition, create any dierctories in the path that don't exist */
  827.     if( pathensure(name) == ERROR)
  828.         return ERROR;
  829.  
  830.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  831.  
  832.     p = name + 1 + strlen(name);
  833.     if (*p)
  834.     {    /* file coming from Unix or DOS system */
  835.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  836. /* NA to atari
  837.             if (Filemode & UNIXFILE)
  838.                 ++Thisbinary; 
  839. */
  840.         if (Verbose)
  841.         {
  842.             fprintf(stderr,
  843.             "\nIncoming:\n\tName:\t%s\n\tBytes:\t%ld\n\tModTime: %ld\n\tMode:\t%o\n\n",
  844.               name, Bytesleft, Modtime, Filemode);
  845.  
  846. #ifdef RDEBUG
  847.             if(logf != (FILE *)NULL)
  848.                 fprintf(logf,  "Incoming: %s %ld %lo %o\n",
  849.                   name, Bytesleft, Modtime, Filemode);
  850. #endif
  851.  
  852.         }
  853.     }
  854.     else
  855.     {        /* File coming from CP/M system */
  856.         for (p=name; *p; ++p)        /* change / to _ */
  857.             if ( *p == '/')
  858.                 *p = '_';
  859.  
  860.         if ( *--p == '.')        /* zap trailing period */
  861.             *p = 0;
  862.     }
  863.     
  864.     strcpy(Pathname, name);
  865.     if (Verbose)
  866.     {
  867.         fprintf(stderr,  "Receiving %s %s [mode %s]\n\n",
  868.           name, Thisbinary?"BIN":"ASCII", openmode);
  869.  
  870. #ifdef RDEBUG
  871.         if(logf != (FILE *)NULL)
  872.             fprintf(logf,  "Receiving %s %s %s\n",
  873.               name, Thisbinary?"BIN":"ASCII", openmode);
  874. #endif
  875.  
  876.     }
  877.  
  878.  
  879.     if ((fout=stfopen(name, openmode)) <= 0)
  880.         return ERROR;
  881.  
  882.     return OK;
  883. }
  884.  
  885. /*
  886.  * Putsec writes the n characters of buf to receive file fout.
  887.  *  If not in binary mode,  all characters
  888.  *  starting with CPMEOF are discarded.
  889.  */
  890. putsec(buf, n)
  891. unsigned char *buf;
  892. register int n;
  893. {
  894.     register unsigned char *p;
  895.  
  896.     if (Thisbinary)
  897.     {
  898.         for (p=buf; --n>=0; p++ )
  899.         {
  900.             if(stputc( *p, fout) < 0)
  901.             {
  902.                 fprintf("\r\nError while Writing file\n");
  903.                 return ERROR;
  904.             }
  905.         }
  906.     }
  907.     else
  908.     {
  909.         if (Eofseen)
  910.             return OK;
  911.  
  912.         for (p=buf; --n>=0; p++ )
  913.         {
  914.             if (*p == CPMEOF)
  915.             {
  916.                 Eofseen=TRUE;
  917.                 return OK;
  918.             }
  919.             if(*p == '\n')
  920.             {
  921.                 if(stputc('\r' ,fout) < 0)
  922.                 {
  923.                     fprintf("\r\nError while Writing file\n");
  924.                     return ERROR;
  925.                 }
  926.             }
  927.             if(stputc(*p ,fout) < 0)
  928.             {
  929.                 fprintf("\r\nError while Writing file\n");
  930.                 return ERROR;
  931.             }
  932.         }
  933.     }
  934.  
  935.     return OK;
  936. }
  937.  
  938. /*
  939.  * Log an error only if high verbose
  940.  */
  941. /*VARARGS1*/
  942. llog(s,p,u)
  943. char *s;
  944. int p, u;
  945. {
  946.     if (Verbose < 3)
  947.         return;
  948. #ifdef RDEBUG
  949.     fprintf(logf, "error %d: ", errors);
  950.     fprintf(logf, s, p, u);
  951. #endif
  952.  
  953.     fprintf(stderr, "\nerror %d: ", errors);
  954.     fprintf(stderr, s, p, u);
  955. }
  956.  
  957. /*
  958.  * Log an error if verbose
  959.  */
  960.  
  961. /*VARARGS1*/
  962. log2(s,p,u)
  963. char *s;
  964. int p, u;
  965. {
  966.     if (!Verbose)
  967.         return;
  968.     fprintf(stderr, "\nerror %d: ", errors);
  969.     fprintf(stderr, s, p, u);
  970.  
  971. #ifdef RDEBUG
  972.     if(Verbose > 3)
  973.     {
  974.         fprintf(logf, "error %d: ", errors);
  975.         fprintf(logf, s, p, u);
  976.     }
  977. #endif
  978.  
  979. }
  980.  
  981. report(sct)
  982. int sct;
  983. {
  984.     if (Verbose>1)
  985.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  986. }
  987.  
  988. lreport(sct)
  989. long sct;
  990. {
  991.     if (Verbose>1)
  992.         fprintf(stderr,"%06ld%c",sct,lsct%10? ' ' : '\r');
  993.     lsct++;
  994. }
  995.  
  996.  
  997. /*
  998.  * If called as rb use YMODEM protocol
  999.  */
  1000. chkinvok(s)
  1001. char *s;
  1002. {
  1003.     Progname = s;
  1004.     if (s[0]=='r' && s[1]=='b')
  1005.         Nozmodem = TRUE;
  1006. }
  1007.  
  1008.  
  1009. /*
  1010.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1011.  *  Handles ZSINIT frame
  1012.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1013.  *   ZCOMPL if transaction finished,  else 0
  1014.  */
  1015. tryz()
  1016. {
  1017.     register int n;
  1018.     register int cmdzack1flg;
  1019.  
  1020.     if (Nozmodem)        /* Check for "rb" program name */
  1021.         return 0;
  1022.  
  1023.  
  1024.     for (n=Zmodem?10:5; --n>=0; )
  1025.     {
  1026.         /* Set buffer length (0) and capability flags */
  1027.         stohdr(0L);
  1028.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; /* of course we can break */
  1029.  
  1030.         zshhdr(tryzhdrtype, Txhdr);
  1031. /*        zshhdr(Badclose?ZFERR:ZRINIT, Txhdr); */
  1032. again:
  1033.         switch (zgethdr(Rxhdr, 0))
  1034.         {
  1035.         case ZRQINIT:
  1036.             continue;
  1037.         case ZEOF:
  1038.             continue;
  1039.         case TIMEOUT:
  1040.             continue;
  1041.         case ZFILE:
  1042.             zconv = Rxhdr[ZF0];
  1043.             zmanag = Rxhdr[ZF1];
  1044.             ztrans = Rxhdr[ZF2];
  1045.             tryzhdrtype = ZRINIT;
  1046.             Badclose = FALSE;
  1047.             if (zrdata(secbuf, KSIZE) == GOTCRCW)
  1048.                 return ZFILE;
  1049.             zshhdr(ZNAK, Txhdr);
  1050.             goto again;
  1051.         case ZSINIT:
  1052.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW)
  1053.             {
  1054.                 zshhdr(ZACK, Txhdr);
  1055.                 goto again;
  1056.             }
  1057.             zshhdr(ZNAK, Txhdr);
  1058.             goto again;
  1059.         case ZFREECNT:
  1060.             stohdr(~0L);
  1061.             zshhdr(ZACK, Txhdr);
  1062.             goto again;
  1063.         case ZCOMMAND:
  1064.             cmdzack1flg = Rxhdr[ZF0];
  1065.             if (zrdata(secbuf, KSIZE) == GOTCRCW)
  1066.             {
  1067.                 if (cmdzack1flg & ZCACK1)
  1068.                     stohdr(0L);
  1069.                 else
  1070.                     stohdr((long)sys2(secbuf));
  1071.                 PURGELINE;    /* dump impatient questions */
  1072.                 do {
  1073.                     zshhdr(ZCOMPL, Txhdr);
  1074.                 }
  1075.                 while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN);
  1076.                 ackbibi();
  1077.                 if (cmdzack1flg & ZCACK1)
  1078.                     exec2(secbuf);
  1079.                 return ZCOMPL;
  1080.             }
  1081.             zshhdr(ZNAK, Txhdr); goto again;
  1082.         case ZCOMPL:
  1083.             goto again;
  1084.         default:
  1085.             continue;
  1086.         case ZFIN:
  1087.             ackbibi(); return ZCOMPL;
  1088.         case ZCAN:
  1089.             return ERROR;
  1090.         }
  1091.     }
  1092.     return 0;
  1093. }
  1094.  
  1095. /*
  1096.  * Receive 1 or more files with ZMODEM protocol
  1097.  */
  1098. rzfiles()
  1099. {
  1100.     register int c;
  1101.  
  1102.     for (;;) {
  1103.         switch (c = rzfile()) {
  1104.         case ZEOF:
  1105.         case ZSKIP:
  1106.             switch (tryz()) {
  1107.             case ZCOMPL:
  1108.                 return OK;
  1109.             default:
  1110.                 return ERROR;
  1111.             case ZFILE:
  1112.                 break;
  1113.             }
  1114.             continue;
  1115.         default:
  1116.             return c;
  1117.         case ERROR:
  1118.             return ERROR;
  1119.         }
  1120.     }
  1121. }
  1122.  
  1123. /*
  1124.  * Receive a file with ZMODEM protocol
  1125.  *  Assumes file name frame is in secbuf
  1126.  */
  1127. rzfile()
  1128. {
  1129.     register int c, n;
  1130.     long rxbytes;
  1131.  
  1132.     Eofseen=FALSE;
  1133.     if (procheader(secbuf) == ERROR) {
  1134.         return (tryzhdrtype = ZSKIP);
  1135. /*        zshhdr(ZSKIP, Txhdr);
  1136.         return ZSKIP; */
  1137.     }
  1138.  
  1139.     n = 10; rxbytes = 0L;
  1140.  
  1141.     for (;;)
  1142.     {
  1143.         stohdr(rxbytes);
  1144.         zshhdr(ZRPOS, Txhdr);
  1145. nxthdr:
  1146.         switch (c = zgethdr(Rxhdr, 0)) {
  1147.         default:
  1148.             vfile("rzfile: zgethdr returned %d", c);
  1149.             return ERROR;
  1150.         case ZNAK:
  1151.         case TIMEOUT:
  1152.             if ( --n < 0)
  1153.             {
  1154.                 vfile("rzfile: zgethdr returned %d", c);
  1155.                 return ERROR;
  1156.             }
  1157.         case ZFILE:
  1158.             zrdata(secbuf, KSIZE);
  1159.             continue;
  1160.         case ZEOF:
  1161.             /* ++jrb */
  1162.             if (rclhdr(Rxhdr) != rxbytes)
  1163.             {
  1164.                 /*
  1165.                      * Ignore eof if it's at wrong place - force
  1166.                      *  a timeout because the eof might have gone
  1167.                      *  out before we sent our zrpos.
  1168.                      */
  1169.  
  1170.                     errors = 0;  goto nxthdr;
  1171.             }
  1172. /* --jrb            if (rclhdr(Rxhdr) != rxbytes)
  1173.             {
  1174.                 continue;
  1175.             } */
  1176.             if (closeit())
  1177.             {
  1178.                 tryzhdrtype = ZFERR;
  1179.                 Badclose = TRUE;
  1180.                 vfile("rzfile: closeit returned <> 0");
  1181.                 return ERROR;
  1182.             }
  1183.             vfile("rzfile: normal EOF");
  1184.             return c;
  1185.         case ERROR:    /* Too much garbage in header search error */
  1186.             if ( --n < 0)
  1187.             {
  1188.                 vfile("rzfile: zgethdr returned %d", c);
  1189.                 return ERROR;
  1190.             }
  1191.             zmputs(Attn);
  1192.             continue;
  1193.         case ZDATA:
  1194.             n = 10;
  1195.             if (rclhdr(Rxhdr) != rxbytes)
  1196.             {
  1197.                 zmputs(Attn);
  1198.                 continue;
  1199.             }
  1200. moredata:
  1201.             switch (c = zrdata(secbuf, KSIZE))
  1202.             {
  1203.             case ZCAN:
  1204.                 vfile("rzfile: zgethdr returned %d", c);
  1205.                 return ERROR;
  1206.             case ERROR:    /* CRC error */
  1207.                 if ( --n < 0)
  1208.                 {
  1209.                     vfile("rzfile: zgethdr returned %d", c);
  1210.                     return ERROR;
  1211.                 }
  1212.                 zmputs(Attn);
  1213.                 continue;
  1214.             case TIMEOUT:
  1215.                 if ( --n < 0)
  1216.                 {
  1217.                     vfile("rzfile: zgethdr returned %d", c);
  1218.                     return ERROR;
  1219.                 }
  1220.                 continue;
  1221.             case GOTCRCW:
  1222.                 if(putsec(secbuf, Rxcount) == ERROR)
  1223.                     return ERROR;
  1224.                 rxbytes += Rxcount;
  1225.                 lreport(rxbytes);
  1226.                 stohdr(rxbytes);
  1227.                 zshhdr(ZACK, Txhdr);
  1228.                 goto nxthdr;
  1229.             case GOTCRCQ:
  1230.                 if(putsec(secbuf, Rxcount) == ERROR)
  1231.                     return ERROR;
  1232.                 rxbytes += Rxcount;
  1233.                 lreport(rxbytes);
  1234.                 stohdr(rxbytes);
  1235.                 zshhdr(ZACK, Txhdr);
  1236.                 goto moredata;
  1237.             case GOTCRCG:
  1238.                 if(putsec(secbuf, Rxcount) == ERROR)
  1239.                     return ERROR;
  1240.                 rxbytes += Rxcount;
  1241.                 lreport(rxbytes);
  1242.                 goto moredata;
  1243.             case GOTCRCE:
  1244.                 if(putsec(secbuf, Rxcount) == ERROR)
  1245.                     return ERROR;
  1246.                 rxbytes += Rxcount;
  1247.                 lreport(rxbytes);
  1248.                 goto nxthdr;
  1249.             }
  1250.         }
  1251.     }
  1252. }
  1253.  
  1254. /*
  1255.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1256.  *   and \335 (break signal)
  1257.  */
  1258. zmputs(s)
  1259. char *s;
  1260. {
  1261.     register int c;
  1262.  
  1263.     while (*s) {
  1264.         switch (c = *s++) {
  1265.         case '\336':
  1266.             stsleep(1); continue;
  1267.         case '\335':
  1268.             sendbrk(); continue;
  1269.         default:
  1270.             sendline(c);
  1271.         }
  1272.     }
  1273. }
  1274.  
  1275.  
  1276.  
  1277. /*
  1278.  * Close the receive dataset, return OK or ERROR
  1279.  */
  1280. closeit()
  1281. {
  1282.     unsigned int timep[2];
  1283.  
  1284.     if (stfclose(fout) != 0) {
  1285.         fprintf(stderr, "\r\nfile close ERROR\n");
  1286.         return ERROR;
  1287.     }
  1288.     fout = (-1);
  1289.  
  1290.     if (Modtime) {
  1291.         unix2st(Modtime, &timep[0], &timep[1]);
  1292.         touch(Pathname, timep);
  1293.     }
  1294.  
  1295.     /* if it is read only by owner on remote, then it is set
  1296.      * to read only on the ST, all other file modes are
  1297.      * irrelevant.
  1298.      */
  1299.     if (Filemode)
  1300.     {
  1301.         unsigned int fmode;
  1302.  
  1303.         fmode = (unsigned int)(Filemode & 000777);
  1304.         if( ((fmode & 0200) == 0) && ((fmode & 0400) != 0) )
  1305.         {
  1306.             /* it is readonly by owner on the remote, so
  1307.              * make it read only on the ST too
  1308.              */
  1309.             Fattrib(Pathname, 1, 0x01);
  1310.         }
  1311.     }
  1312.     fprintf(stderr,"\n\n%s Closed\n\n", Pathname);
  1313.     lsct = 1;
  1314.     return OK;
  1315. }
  1316.  
  1317. /*
  1318.  * Ack a ZFIN packet, let byegones be byegones
  1319.  */
  1320. ackbibi()
  1321. {
  1322.     register int n;
  1323.  
  1324.     vfile("ackbibi:");
  1325.     Readnum = 1;
  1326.     stohdr(0L);
  1327.     for (n=4; --n>=0; )
  1328.     {
  1329.         zshhdr(ZFIN, Txhdr);
  1330.         for (;;) {
  1331.             switch (readline(100))
  1332.             {
  1333.             case 'O':
  1334.                 readline(1);    /* Discard 2nd 'O' */
  1335.                 /* ***** FALL THRU TO ***** */
  1336.             case TIMEOUT:
  1337.                 vfile("ackbibi complete");
  1338.                 return;
  1339.             default:
  1340.                 break;
  1341.             }
  1342.         }
  1343.     }
  1344. }
  1345.  
  1346.  
  1347. /*
  1348.  * Strip leading ! if present, do shell escape. 
  1349.  */
  1350. sys2(s)
  1351. register char *s;
  1352. {
  1353.     if (*s == '!')
  1354.         ++s;
  1355.     return stsystem(s);
  1356. }
  1357. /*
  1358.  * Strip leading ! if present, do exec.
  1359.  */
  1360. exec2(s)
  1361. char *s;
  1362. {
  1363. /** Are you kidding
  1364.     if (*s == '!')
  1365.         ++s;
  1366.     mode(0);
  1367.     execl("/bin/sh", "sh", "-c", s); 
  1368. **/
  1369. }
  1370.  
  1371. /*
  1372.  * Touch a file
  1373.  */
  1374. #undef Fdatime        /* There exist brain damaged versions of osbind.h */
  1375. #define    Fdatime(a,b,c)    gemdos(0x57,a,b,c)
  1376.  
  1377.  
  1378. touch(name, timep)
  1379. char *name;
  1380. unsigned int *timep;
  1381. {
  1382.     register int handle;
  1383.  
  1384.     if((handle = Fopen(name, 0)) < 0)
  1385.     {
  1386.         fprintf(stderr,"*WARNING* Could not set file modification time for %s\n",
  1387.             name);
  1388.         return;
  1389.     }
  1390.  
  1391.  
  1392.     Fdatime(timep, handle, 1);
  1393.     Fclose(handle);
  1394. }
  1395.